from datetime import date, datetime
from typing import Any

from aiogram import types
from aiogram_dialog import Dialog, DialogManager, Window
from aiogram_dialog.widgets.input import TextInput
from aiogram_dialog.widgets.kbd import Back, Button, Calendar, Cancel, Group
from aiogram_dialog.widgets.text import Const, Format
from apscheduler.schedulers.asyncio import AsyncIOScheduler

from app.bot.dialog.dialog_states import MailingSG
from app.bot.dialog.widgets import LocaleText
from app.bot.services.date_time import get_date_time
from app.bot.services.loggers import logger
from app.bot.services.scheduler import jobs


async def get_current_time(dialog_manager: DialogManager, **kwargs):
    return {"current_time": get_date_time()}


async def set_mailing_settings(
    call: types.CallbackQuery, widget: Any, manager: DialogManager
):

    manager.dialog_data["mailing_users"] = widget.widget_id

    await manager.switch_to(MailingSG.mailing_text)


async def set_mailing_text(
    message: types.Message, widget: Any, manager: DialogManager, mailing_text: str
):

    manager.dialog_data["mailing_text"] = mailing_text

    await manager.switch_to(MailingSG.mailing_text_eng)


async def set_mailing_text_eng(
    message: types.Message, widget: Any, manager: DialogManager, mailing_text_eng: str
):

    manager.dialog_data["mailing_text_eng"] = mailing_text_eng

    await manager.switch_to(MailingSG.select_date)


async def set_mailing_date(
    call: types.CallbackQuery, widget, manager: DialogManager, selected_date: date
):
    manager.dialog_data["mailing_date"] = str(selected_date)

    await manager.switch_to(MailingSG.select_time)


async def set_mailing_time(
    message: types.Message, widget: Any, manager: DialogManager, mailing_time: str
):

    try:
        datetime.strptime(mailing_time, "%H:%M:%S")
    except ValueError:
        await message.answer("Время не в том формате")
        return

    manager.dialog_data["mailing_time"] = mailing_time

    await manager.switch_to(MailingSG.confirm_mailing)


async def confirm_mailing(
    call: types.CallbackQuery, widget: Any, manager: DialogManager
):
    scheduler: AsyncIOScheduler = manager.middleware_data.get("scheduler")
    db_session = manager.middleware_data.get("db_session")

    selected_date: str = manager.dialog_data.get("mailing_date")
    mailing_time: str = manager.dialog_data.get("mailing_time")

    date_and_time = datetime.combine(
        datetime.strptime(selected_date, "%Y-%m-%d").date(),
        datetime.strptime(mailing_time, "%H:%M:%S").time(),
    )

    scheduler.add_job(
        jobs.notify_users,
        run_date=date_and_time,
        args=(
            manager.middleware_data.get("bot"),
            db_session,
            manager.middleware_data.get("config"),
            manager.dialog_data.get("mailing_text"),
            manager.dialog_data.get("mailing_text_eng"),
            manager.dialog_data.get("mailing_users"),
        ),
    )
    logger.info("В планировщик добавлена задача на рассылку")

    if widget.widget_id == "yes":
        await call.answer("Рассылка запланирована")

    elif widget.widget_id == "no":
        await call.answer("Рассылка отменена")

    await manager.done()


mailing_start_window = Window(
    Const("По кому делать рассылку?"),
    Group(
        Button(
            Const("По всем участникам"), id="all_users", on_click=set_mailing_settings
        ),
        Button(
            Const("По незарегистрированным"),
            id="not_registered",
            on_click=set_mailing_settings,
        ),
        Button(
            Const("По зарегистрированным"),
            id="registered",
            on_click=set_mailing_settings,
        ),
        width=2,
    ),
    Cancel(LocaleText("back-btn")),
    state=MailingSG.start_mailing,
)

mailing_text_window = Window(
    Const("Введи текст рассылки"),
    TextInput("mailing_text", str, on_success=set_mailing_text),
    Back(LocaleText("back-btn")),
    state=MailingSG.mailing_text,
)

mailing_text_eng_window = Window(
    Const("Введи текст рассылки для англоязычных пользователей"),
    TextInput("mailing_text_eng", str, on_success=set_mailing_text_eng),
    Back(LocaleText("back-btn")),
    state=MailingSG.mailing_text_eng,
)

select_date_window = Window(
    Const("Выбери дату рассылки"),
    Calendar(id="calendar", on_click=set_mailing_date),
    Back(LocaleText("back-btn")),
    state=MailingSG.select_date,
)

select_time_window = Window(
    Const("Выбери время рассылки в формате 23:59:59"),
    Format("Текущее время: {current_time}"),
    TextInput("mailing_time", str, on_success=set_mailing_time),
    Back(LocaleText("back-btn")),
    state=MailingSG.select_time,
    getter=get_current_time,
)

confirm_mailing_window = Window(
    Const("Подтвердить рассылку?"),
    Button(Const("Да"), id="yes", on_click=confirm_mailing),
    Button(Const("Нет"), id="no", on_click=confirm_mailing),
    Back(LocaleText("back-btn")),
    state=MailingSG.confirm_mailing,
)

mailing_dialog = Dialog(
    mailing_start_window,
    mailing_text_window,
    mailing_text_eng_window,
    select_date_window,
    select_time_window,
    confirm_mailing_window,
)
